package org.nudt.system.service

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import jakarta.persistence.EntityManager
import jakarta.persistence.criteria.Predicate
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.nudt.common.exception.BadRequestException
import org.nudt.common.model.PageData
import org.nudt.common.model.Type
import org.nudt.common.model.Video
import org.nudt.common.model.dto.PlayUrl
import org.nudt.common.repository.TypeRepository
import org.nudt.common.repository.VideoRepository
import org.nudt.common.utils.FileUtil
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
import java.io.File
import java.io.FileOutputStream
import java.util.*


@Service
class SysVideoService(
    private val videoRepository: VideoRepository,
    private val typeRepository: TypeRepository,
    @Value("\${file.pic-path}") private val picPath: String,
    private val objectMapper: ObjectMapper,
    private val entityManager: EntityManager,
    private val httpClient: OkHttpClient
) {
    private val logger = LoggerFactory.getLogger(SysVideoService::class.java)
    
    fun getVideoById(id: Int): Video? {
        return videoRepository.getVideoById(id)
    }
    
    fun deleteVideoById(id: Int) {
        return videoRepository.deleteById(id)
    }
    
    fun updateVideo(video: Video): Video {
        val originUrlList = video.playUrl
        if (originUrlList.startsWith("ftp")) {
            val list = originUrlList.split('\n')
            val playUrlList = mutableListOf<PlayUrl>()
            list.forEach {
                var url = it.replace("ftp://video@192.168.0.173", "http://192.168.0.173:83")
                val dot = it.lastIndexOf('/')
                if (dot > -1 && dot < it.length - 1) {
                    val fileName = it.substring(dot + 1)
                    var name = fileName.substring(0, fileName.lastIndexOf('.'))
                    if (list.size == 1) {
                        name = "HD"
                    }
                    val playUrl = PlayUrl(name, url)
                    playUrlList.add(playUrl)
                }
            }
            video.playUrl = objectMapper.writeValueAsString(playUrlList)
        }
        
        return videoRepository.save(video)
    }
    
    fun getVideoTypeList(): MutableList<Type> {
        return typeRepository.findAll()
    }
    
    fun getVideoList(
        // 视频名称，可以为空
        videoName: String?,
        // 演员，可以为空
        actor: String?,
        // 地区，可以为空
        area: String?,
        // 年份，可以为空
        year: String?,
        // 分页请求对象
        pageRequest: PageRequest
    ): PageData<Video?> {
        // 获取实体管理器中的CriteriaBuilder对象，用于构建查询条件
        val cb = entityManager.criteriaBuilder
        // 创建一个CriteriaQuery对象，用于查询Video实体
        val cq = cb.createQuery(Video::class.java)
        // 从Video实体中获取根对象
        val video = cq.from(Video::class.java)
        // 创建一个可变的条件列表
        val predicates = mutableListOf<Predicate>()
        
        // 如果视频名称不为空或不是空白字符串，则添加一个like条件
        if (!videoName.isNullOrBlank()) {
            predicates.add(cb.like(video.get<String>("videoName"), "%$videoName%"))
        }
        
        // 如果演员不为空或不是空白字符串，则添加一个like条件
        if (!actor.isNullOrBlank()) {
            predicates.add(cb.like(video.get<String>("actor"), "%$actor%"))
        }
        
        // 如果地区不为空或不是空白字符串，则添加一个like条件
        if (!area.isNullOrBlank()) {
            predicates.add(cb.like(video.get<String>("area"), "%$area%"))
        }
        
        // 如果年份不为空或不是空白字符串，则添加一个equal条件
        if (!year.isNullOrBlank()) {
            predicates.add(cb.equal(video.get<String>("year"), year))
        }
        
        // 将条件列表添加到查询条件中
        cq.where(*predicates.toTypedArray())
        
        // 添加按createdAt排序的条件
        cq.orderBy(cb.desc(video.get<Int>("id")))
        
        // 创建一个TypedQuery对象，用于执行查询
        val typedQuery = entityManager.createQuery(cq)
        // 设置查询的起始结果位置
        typedQuery.firstResult = (pageRequest.pageNumber - 1) * pageRequest.pageSize
        // 设置查询的最大结果数量
        typedQuery.maxResults = pageRequest.pageSize
        
        // 获取查询结果列表
        val videos = typedQuery.resultList
        
        // 获取总记录数
        val countQuery = cb.createQuery(Long::class.java)
        val countRoot = countQuery.from(Video::class.java)
        
        val predicatesToCount = mutableListOf<Predicate>()
        
        // 如果视频名称不为空或不是空白字符串，则添加一个like条件
        if (!videoName.isNullOrBlank()) {
            predicatesToCount.add(cb.like(countRoot.get("videoName"), "%$videoName%"))
        }
        
        // 如果演员不为空或不是空白字符串，则添加一个like条件
        if (!actor.isNullOrBlank()) {
            predicatesToCount.add(cb.like(countRoot.get("actor"), "%$actor%"))
        }
        
        // 如果地区不为空或不是空白字符串，则添加一个like条件
        if (!area.isNullOrBlank()) {
            predicatesToCount.add(cb.like(countRoot.get("area"), "%$area%"))
        }
        
        // 如果年份不为空或不是空白字符串，则添加一个equal条件
        if (!year.isNullOrBlank()) {
            predicatesToCount.add(cb.equal(countRoot.get<String>("year"), year))
        }
        
        countQuery.select(cb.count(countRoot))
        countQuery.where(*predicatesToCount.toTypedArray())
        val total = entityManager.createQuery(countQuery).singleResult
        
        return PageData(pageRequest.pageNumber, pageRequest.pageSize, total, videos)
    }
    
    /**
     * 保存视频信息，如果已经存在则不更新
     *
     * @param video 视频对象
     * @return 保存后的视频对象
     */
    fun saveNotUpdate(video: Video) {
        // 获取视频名称
        video.videoName.let {
            // 根据视频名称查询数据库中是否存在该视频信息
            val videoInDb = videoRepository.getTopByVideoName(it)
            if (videoInDb == null) {
                // 如果不存在，则将id设为null并保存新视频信息
                video.id = null
                video.status = false
                video.coverUrl = "http://192.168.0.173:88/" + video.coverUrl
                
                download(true, video)
            }
        }
    }
    
    /**
     * 判断是否已经存在视频信息
     *
     * @param video 视频对象
     * @return 如果存在则返回true，否则返回false
     */
    fun exists(video: Video): Boolean {
        // 获取视频名称
        video.videoName.let {
            // 根据视频名称查询数据库中是否存在该视频信息
            val videoInDb = videoRepository.getTopByVideoName(it)
            return videoInDb != null
        }
    }
    
    /**
     * 获取到还没同步照片的视频列表
     *
     * @return 视频的分页结果，包含总记录数、当前页码、每页显示的记录数以及视频列表
     */
    fun findByVodPicStartingWith(): List<Video> {
        // 根据关键字查询数据库中符合条件的视频信息
        val videoList = videoRepository.findByCoverUrlStartingWith("upload")
        return videoList
    }
    
    fun updateSerial() {
        val videoList = videoRepository.findBySerialEquals(0)
        videoList.forEach {
            it.playUrl
            val ref = object : TypeReference<List<PlayUrl>?>() {}
            try {
                val list = objectMapper.readValue(it.playUrl, ref)
                list?.let { urlList ->
                    it.serial = urlList.size
                }
            } catch (e: Exception) {
                logger.error(e.message)
            }
            
        }
        videoRepository.saveAll(videoList)
    }
    
    fun updateUrl() {
        val videoList = videoRepository.findAll()
        videoList.forEach {
            val urlList = mutableListOf<PlayUrl>()
            if (it.playUrl.contains('#')) {
                // 多集
                val playUrls: Array<String> = it.playUrl.split("#").toTypedArray()
                for (i in playUrls.indices) {
                    if (playUrls[i].endsWith("mp4") || playUrls[i].endsWith("mkv") || playUrls[i].endsWith("rmvb") || playUrls[i].endsWith("avi")) {
                        val singleUrl = playUrls[i]
                        if (singleUrl.contains("$")) {
                            val vodData = singleUrl.split("$").toTypedArray()
                            if (vodData.size == 2) {
                                val url: String = if (vodData[1].startsWith("http")) {
                                    vodData[1]
                                } else {
                                    "http://192.168.0.173:83" + vodData[1]
                                }
                                val playUrl = PlayUrl(vodData[0], url)
                                urlList.add(playUrl)
                            }
                        }
                    }
                }
            } else {
                // 单集
                if (it.playUrl.endsWith("mp4") || it.playUrl.endsWith("mkv") || it.playUrl.endsWith("rmvb") || it.playUrl.endsWith("avi")) {
                    val singleUrl = it.playUrl
                    if (singleUrl.contains("$")) {
                        val vodData = singleUrl.split("$").toTypedArray()
                        if (vodData.size == 2) {
                            val url: String = if (vodData[1].startsWith("http")) {
                                vodData[1]
                            } else {
                                "http://192.168.0.173:83" + vodData[1]
                            }
                            val playUrl = PlayUrl(vodData[0], url)
                            urlList.add(playUrl)
                        }
                    }
                }
            }
            it.playUrl = objectMapper.writeValueAsString(urlList)
            videoRepository.save(it)
        }
    }
    
    /**
     * 下载图片
     *
     * @param exists true代表已经存在视频信息
     * @param video 视频对象
     */
    fun download(exists: Boolean, video: Video) {
        // 获取视频类型ID和封面URL
        val typeId = video.typeId
        var url = video.coverUrl
        
        if (!url.startsWith("http")) {
            url = "http://192.168.0.173/" + url
        }
        
        logger.info(Thread.currentThread().name + "----开始下载 " + typeId + "---" + url)
        
        // 构建HTTP请求
        val request = Request.Builder()
            .url(url)
            .build()
        
        // 获取文件扩展名
        val fileExt = FileUtil.getExtensionName(url)
        // 支持的图片格式
        val imageTypes = "jpg png jpeg webp"
        if (fileExt != null && !imageTypes.contains(fileExt)) {
            throw BadRequestException("文件格式错误！, 仅支持 $imageTypes 格式")
        }
        // 生成文件名
        val fileName = "${UUID.randomUUID().toString().replace("-", "")}.$fileExt"
        val destPath = "$picPath$typeId/$fileName"
        try {
            val outputFile = File(destPath).getCanonicalFile()
            // 检测是否存在目录
            if (!outputFile.getParentFile().exists()) {
                if (!outputFile.getParentFile().mkdirs()) {
                    logger.error("error url: $url")
                    throw BadRequestException("have no dir")
                }
            }
            
            val response: Response = httpClient.newCall(request).execute() // 执行请求
            
            if (response.isSuccessful) {
                // 将响应体写入文件
                response.body.let { body ->
                    FileOutputStream(outputFile).use { outputStream ->
                        outputStream.write(body.bytes())
                    }
                    logger.info("图片下载成功，保存路径: ${outputFile.absolutePath}")
                    val pic = "http://192.168.0.177/upload/video/$typeId/$fileName"
                    video.coverUrl = pic
                    // 如果是新的视频，则清空vodId，确保插入
                    if (!exists) {
                        video.id = null
                    }
                    //保存一下原始图片信息
                    video.coverHUrl = pic
                    videoRepository.save(video)
                }
            } else {
                logger.info("请求失败，状态码: ${response.code}")
            }
        } catch (e: Exception) {
            logger.info("下载失败: ${e.message}")
        }
    }
}